package com.skyworth.web.shiro.redis;

import org.apache.shiro.dao.DataAccessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.Set;

@Service
public class RedisService {

  @Autowired
  protected RedisTemplate redisTemplate;

  public long delByPattern(String pattern) {
    if (!StringUtils.isEmpty(pattern)) {
      return del(this.keys(pattern));
    }
    return 0;
  }

  /**
   * @param keys
   */
  public long del(final Set<String> keys) {
    return (long) redisTemplate.execute(new RedisCallback() {
      public Long doInRedis(RedisConnection connection) throws DataAccessException {
        long result = 0;
        for (String key : keys) {
          result = connection.del(key.getBytes());
        }
        return result;
      }
    });
  }

  /**
   * @param keys
   */
  public long del(final String... keys) {
    return (long) redisTemplate.execute(new RedisCallback() {
      public Long doInRedis(RedisConnection connection) throws DataAccessException {
        long result = 0;
        for (int i = 0; i < keys.length; i++) {
          result = connection.del(keys[i].getBytes());
        }
        return result;
      }
    });
  }

  /**
   * @param key
   * @param value
   * @param liveTime
   */
  public void set(final byte[] key, final byte[] value, final long liveTime) {
    redisTemplate.execute(new RedisCallback() {
      public Long doInRedis(RedisConnection connection) throws DataAccessException {
        connection.set(key, value);
        if (liveTime > 0) {
          connection.expire(key, liveTime);
        }
        return 1L;
      }
    });
  }

  /**
   * @param key
   * @param value
   * @param liveTime
   */
  public void set(String key, String value, long liveTime) {
    this.set(key.getBytes(), value.getBytes(), liveTime);
  }

  /**
   * @param key
   * @param value
   */
  public void set(String key, String value) {
    this.set(key, value, 0L);
  }

  /**
   * @param key
   * @param object
   */
  public void set(String key, Object object) {
    this.set(key.getBytes(), SerializeUtils.serialize(object), 0L);
  }

  /**
   * @param key
   * @param value
   */
  public void set(byte[] key, byte[] value) {
    this.set(key, value, 0L);
  }

  /**
   * @param key
   * @return
   */
  public Object getObject(final String key) {
    return redisTemplate.execute(new RedisCallback() {
      public Object doInRedis(RedisConnection connection) throws DataAccessException {
        return SerializeUtils.deserialize(connection.get(key.getBytes()));
      }
    });
  }

  /**
   * @param key
   * @return
   */
  public String get(final String key) {
    return (String) redisTemplate.execute(new RedisCallback() {
      public String doInRedis(RedisConnection connection) throws DataAccessException {
        try {
          return new String(connection.get(key.getBytes()), "utf-8");
        } catch (UnsupportedEncodingException e) {
          e.printStackTrace();
        }
        return "";
      }
    });
  }

  /**
   * @param pattern
   * @return
   */
  public Set keys(String pattern) {
    return redisTemplate.keys(pattern);
  }

  /**
   * @param key
   * @return
   */
  public boolean exists(final String key) {
    return (boolean) redisTemplate.execute(new RedisCallback() {
      public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
        return connection.exists(key.getBytes());
      }
    });
  }

  /**
   * @return
   */
  public String flushDB() {
    return (String) redisTemplate.execute(new RedisCallback() {
      public String doInRedis(RedisConnection connection) throws DataAccessException {
        connection.flushDb();
        return "ok";
      }
    });
  }

  /**
   * @return
   */
  public long dbSize() {
    return (long) redisTemplate.execute(new RedisCallback() {
      public Long doInRedis(RedisConnection connection) throws DataAccessException {
        return connection.dbSize();
      }
    });
  }

  /**
   * @return
   */
  public String ping() {
    return (String) redisTemplate.execute(new RedisCallback() {
      public String doInRedis(RedisConnection connection) throws DataAccessException {
        return connection.ping();
      }
    });
  }
}
